﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace GW2_Url
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            SearchData sd = new SearchData() { Title = "Guild Wars 2" };
            EnumWindows(new EnumWindowsProc(EnumProc), ref sd);
            ShowWindow(sd.hWnd, ShowWindowCommands.ShowDefault);
            SetForegroundWindow(sd.hWnd);

            //String url = "gw2:[&BEgAAAA=]";
            String url = args[0];

            String message = url.Substring("gw2:".Length);

            System.Windows.Forms.SendKeys.Flush();

            int VK_RETURN_lParam = 0x1c0000; // http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
            int VK_RETURN = 0x0D;


            System.Threading.Thread.Sleep(200);

            PostMessage_PressKeyDown((int)sd.hWnd, VK_RETURN, VK_RETURN_lParam);
            System.Threading.Thread.Sleep(10);
            PostMessage_PressKeyUp((int)sd.hWnd, VK_RETURN, VK_RETURN_lParam);

            System.Threading.Thread.Sleep(20);

            System.Windows.Forms.SendKeys.SendWait("{/}s ");

            System.Windows.Forms.SendKeys.Flush();

            message = Regex.Replace(message, "([\\[\\]()+\\\\^%~{}])", "{$1}", RegexOptions.None);
            System.Windows.Forms.SendKeys.SendWait(message);

            System.Windows.Forms.SendKeys.Flush();

            System.Threading.Thread.Sleep(100);

            PostMessage_PressKeyDown((int)sd.hWnd, VK_RETURN, VK_RETURN_lParam);
            System.Threading.Thread.Sleep(10);
            PostMessage_PressKeyUp((int)sd.hWnd, VK_RETURN, VK_RETURN_lParam);

            System.Windows.Forms.SendKeys.Flush();

            WINDOWINFO info = new WINDOWINFO();
            info.cbSize = (uint)Marshal.SizeOf(info);
            GetWindowInfo(sd.hWnd, ref info);

            int MOUSEEVENTF_LEFTDOWN = 0x0002;
            int MOUSEEVENTF_LEFTUP = 0x0004;

            System.Threading.Thread.Sleep(100);

            System.Windows.Forms.Cursor.Position = new System.Drawing.Point((info.rcClient.left + 150), (info.rcClient.bottom - 60));
            mouse_event((uint)MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
            mouse_event((uint)MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);

        }

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);

        [StructLayout(LayoutKind.Sequential)]
        struct RECT
        {
            public int left, top, right, bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct WINDOWINFO
        {
            public uint cbSize;
            public RECT rcWindow;
            public RECT rcClient;
            public uint dwStyle;
            public uint dwExStyle;
            public uint dwWindowStatus;
            public uint cxWindowBorders;
            public uint cyWindowBorders;
            public ushort atomWindowType;
            public ushort wCreatorVersion;

            public WINDOWINFO(Boolean? filler)
                : this()   // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
            {
                cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
            }

        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);

        ///summary>
        /// Virtual Messages
        /// </summary>
        public enum WMessages : int
        {
            WM_LBUTTONDOWN = 0x201, //Left mousebutton down
            WM_LBUTTONUP = 0x202,  //Left mousebutton up
            WM_LBUTTONDBLCLK = 0x203, //Left mousebutton doubleclick
            WM_RBUTTONDOWN = 0x204, //Right mousebutton down
            WM_RBUTTONUP = 0x205,   //Right mousebutton up
            WM_RBUTTONDBLCLK = 0x206, //Right mousebutton doubleclick
            WM_KEYDOWN = 0x100,  //Key down
            WM_KEYUP = 0x101,   //Key up
            WM_PASTE = 0x302,
            WM_CHAR = 0x102
        }

        public static void PostMessage_PressKeyDown(int hWnd, int Key, int lParam)
        {
            PostMessage(hWnd, (int)WMessages.WM_KEYDOWN, Key, (lParam | 0x0001));
        }

        public static void PostMessage_PressKeyUp(int hWnd, int Key, int lParam)
        {
            PostMessage(hWnd, (int)WMessages.WM_KEYUP, Key, (lParam | 0x0001));
        }


        [DllImport("User32.Dll", CharSet = CharSet.Auto)]
        public static extern Int32 PostMessage(int hWnd, int msg, int wParam, int lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ref SearchData sd);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData lParam);

        public static bool EnumProc(IntPtr hWnd, ref SearchData data)
        {
            StringBuilder sb = new StringBuilder(1024);
            GetWindowText(hWnd, sb, sb.Capacity);
            if (sb.ToString().StartsWith(data.Title))
            {
                data.hWnd = hWnd;
                return false;
            }

            return true;
        }

        enum ShowWindowCommands : int
        {
            /// <summary>
            /// Hides the window and activates another window.
            /// </summary>
            Hide = 0,
            /// <summary>
            /// Activates and displays a window. If the window is minimized or 
            /// maximized, the system restores it to its original size and position.
            /// An application should specify this flag when displaying the window 
            /// for the first time.
            /// </summary>
            Normal = 1,
            /// <summary>
            /// Activates the window and displays it as a minimized window.
            /// </summary>
            ShowMinimized = 2,
            /// <summary>
            /// Maximizes the specified window.
            /// </summary>
            Maximize = 3, // is this the right value?
            /// <summary>
            /// Activates the window and displays it as a maximized window.
            /// </summary>       
            ShowMaximized = 3,
            /// <summary>
            /// Displays a window in its most recent size and position. This value 
            /// is similar to <see cref="Win32.ShowWindowCommand.Normal"/>, except 
            /// the window is not activated.
            /// </summary>
            ShowNoActivate = 4,
            /// <summary>
            /// Activates the window and displays it in its current size and position. 
            /// </summary>
            Show = 5,
            /// <summary>
            /// Minimizes the specified window and activates the next top-level 
            /// window in the Z order.
            /// </summary>
            Minimize = 6,
            /// <summary>
            /// Displays the window as a minimized window. This value is similar to
            /// <see cref="Win32.ShowWindowCommand.ShowMinimized"/>, except the 
            /// window is not activated.
            /// </summary>
            ShowMinNoActive = 7,
            /// <summary>
            /// Displays the window in its current size and position. This value is 
            /// similar to <see cref="Win32.ShowWindowCommand.Show"/>, except the 
            /// window is not activated.
            /// </summary>
            ShowNA = 8,
            /// <summary>
            /// Activates and displays the window. If the window is minimized or 
            /// maximized, the system restores it to its original size and position. 
            /// An application should specify this flag when restoring a minimized window.
            /// </summary>
            Restore = 9,
            /// <summary>
            /// Sets the show state based on the SW_* value specified in the 
            /// STARTUPINFO structure passed to the CreateProcess function by the 
            /// program that started the application.
            /// </summary>
            ShowDefault = 10,
            /// <summary>
            ///  <b>Windows 2000/XP:</b> Minimizes a window, even if the thread 
            /// that owns the window is not responding. This flag should only be 
            /// used when minimizing windows from a different thread.
            /// </summary>
            ForceMinimize = 11
        }

    }
}
